package com.lhl.gencode.auditing;

import cn.hutool.core.util.StrUtil;
import com.lhl.fw.db.annotation.CreatedByPath;
import com.lhl.fw.db.annotation.LastModifiedByPath;
import com.lhl.gencode.annotation.GenCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.data.auditing.AuditingHandler;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.Assert;

import java.lang.reflect.Field;
import java.util.Objects;
import java.util.stream.Stream;

/**
 * @className: MyAuditingHandler
 * @description: TODO 类描述
 * @author: king
 * @date: 2020-09-14 17:11
 **/
@Slf4j
public class JpaAuditingHandler extends AuditingHandler {

    private StringRedisTemplate stringRedisTemplate;
    public JpaAuditingHandler(
            MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> mappingContext,StringRedisTemplate stringRedisTemplate) {
        super(mappingContext);
        this.stringRedisTemplate = stringRedisTemplate;
    }
    @Override
    public <T> T markCreated(T source) {
        log.info("Custom handler");
        Assert.notNull(source, "Entity must not be null!");
        // 拿到创建值类型
        Class<?> sourceClass = source.getClass();
        // 初始化请求值类型的 MetaObject
        MetaObject metaObject = SystemMetaObject.forObject(source);
        // 捕捉到属性上的标记注解 @CreatedByPath 并进行对应的赋值处理
        Stream.of(sourceClass.getDeclaredFields())
                .filter(field -> field.isAnnotationPresent(CreatedByPath.class))
                .forEach(field ->doSetValue(metaObject, field));
        Stream.of(sourceClass.getDeclaredFields())
                .filter(field -> field.isAnnotationPresent(GenCode.class))
                .forEach(field ->doGenCodeSetValue(metaObject, field));
        return super.markCreated(source);
    }
    @Override
    public <T> T markModified(T source) {
        log.info("Custom handler");
        Assert.notNull(source, "Entity must not be null!");
        // 拿到创建值类型
        Class<?> sourceClass = source.getClass();
        // 初始化请求值类型的 MetaObject
        MetaObject metaObject = SystemMetaObject.forObject(source);
        // 捕捉到属性上的标记注解 @LastModifiedByPath 并进行对应的赋值处理
        Stream.of(sourceClass.getDeclaredFields())
                .filter(field -> field.isAnnotationPresent(LastModifiedByPath.class))
                .forEach(field ->doSetValue(metaObject, field));
        return super.markModified(source);
    }
    private void doSetValue(MetaObject metaObject, Field field) {
        // 拿到属性名
        String name = field.getName();
        // 获取属性值
        Object value = metaObject.getValue(name);
        //判断是否有值
        if(Objects.isNull(value)){
            // 把值塞回去
            metaObject.setValue(name, "system");
        }
    }
    private void doGenCodeSetValue(MetaObject metaObject, Field field) {
        // 拿到属性名
        String name = field.getName();
        // 获取属性值
        Object value = metaObject.getValue(name);
        //判断是否有值
        if(Objects.isNull(value)){
            String code = genCode(metaObject,field);
            // 把值塞回去
            metaObject.setValue(name, code);
        }
    }

    private String genCode(MetaObject metaObject,Field field){
        GenCode gc = field.getAnnotation(GenCode.class);
        log.debug("keyName=={}",gc.keyName());
        log.debug("prefix=={}",gc.prefix());
        log.debug("prefixLength=={}",gc.prefixLength());
        log.debug("deField=={}",gc.deField());
        String code = "";
        //获得SpringUtil工具
//        StringRedisTemplate redisTemplate = SpringUtil.getBean(StringRedisTemplate.class);
        //1:查看依赖数据
        String dpFieldName = gc.deField();
        // 获取属性值
        Object value = metaObject.getValue(dpFieldName);
        //判断是否有值
        String key = null;
        if(Objects.isNull(value)){
            key = StrUtil.format("{}:{}",gc.keyName(),gc.prefix());
        }else{
            key = StrUtil.format("{}:{}",gc.keyName(),value.toString());
        }
        Long cl = stringRedisTemplate.boundValueOps(key).increment(1);
        String rc = this.fullKey(cl.intValue(),gc.prefixLength());
        if(Objects.isNull(value)){
            return gc.prefix()+rc;
        }else{
            return value.toString() + "-" +gc.prefix()+rc;
        }

    }

    private String fullKey(int v,int tpv){
        String tp = StrUtil.format("%0{}d",tpv);
        return String.format(tp, v);
    }
}